;***********************************************************************
; Archivo Fuente: TPIntel.asm
; Alumno : Sebastián Dario Wandelow
; Padron : 90991
; 1er Cuatrimestre 2013
;
; Descripción del Programa:
;
; Programa que lee de un archivo una fecha escrita en calendario 
; Juliano en formato zoneado de 5 bytes y la muestra por pantalla 
; en Formato Gregoriano.
; Formato de la fecha Juliana: DDDYY
;
;***********************************************************************

;---------------------
; Segmento de Pila
;---------------------
segment pila stack
	resb 1024

;---------------------
; Segmento de Datos
;---------------------
segment datos data

;--------------
; Archivos
;--------------
	archin        db      "archin.dat",0
	idarch        resw    1
	reg           resb    5
                  db      '$'

;--------------
; Variables
;--------------
	
	cadena		times	5	db	'0'
							db	'$'
	num				resw	1
	
	cantdiasanio	resw	1
	cantdiasmes		resw	1
	diasfebrero		resw	1
	
	aniosalida		resw	1
	messalida		resw	1
	diassalida		resw	1
    
	
	anio			resw	1
	diasJuliano		resw	1
	anioinicio		resw	1
	
	unidad			resw    1
	decena			resw    1
	centena			resw    1
	unidadanio		resw    1
	decenaanio		resw    1
	
	
;-------------------
; Constantes
;-------------------
	diez		dw	10
	cuatro		dw	4
	cien		dw	100
	cuatrocien	dw	400
	
;-------------------
; Mensajes
;-------------------

    barra			db	"/$"
	flecha			db	" -> $"	
	retornocarro	db	10,13,'$'
	msgBienvenida	db	"Conversor Juliano (DDDYY) - Gregoriano (DD/MM/YYYY).$"
	msgErr			db	"Se produjo un error.$"
	
;----------------------
; Segmento de Código
;----------------------

segment codigo code

..start:
	; Inicialización de registro DS y SS
	mov	ax,datos
	mov	ds,ax
	mov	ax,pila
	mov	ss,ax
	
	; imprimo mensaje de bienvenida
	lea	dx,[msgBienvenida]
	mov	ah,9
	int	21h
	lea	dx,[retornocarro]
	mov	ah,9
	int	21h
	
	call	abrirArchivo
	call	leer
	call	cerrarArchivo
	
fin:
	; Fin de la aplicación
	mov	ax,4c00h	; retorno al DOS
	int	21h
	
	
;--------------------------------------------
; Rutina para convertir a formato gregoriano
; Param input: anio, num
;--------------------------------------------
convertirAGregoriano:
	; si (49 < año ingresado < 99) entonces año base es 1900 
	cmp	word[anio],49
	jle	anio2000
	mov	word[anioinicio],1900
	jmp continuar
anio2000:
	; si (0 < año ingresado < 50) entonces año base es 2000 
	mov	word[anioinicio],2000
	jmp continuar
	
continuar:
	mov	ax,[anioinicio]
	add	ax,word[anio]

	mov	[aniosalida],ax
otroAnio:	
	call	obtenterDiasPorAnio
	
	mov	ax,[diasJuliano]
	cmp ax,[cantdiasanio]	; si dias es menor que la cantidad de dias del año
	jle	obtenerMes			; termina el calculo del aniosalida
	
	mov	dx,[cantdiasanio]
	sub	[diasJuliano],dx		; diasingreso - cantdiasanio
	inc	word[aniosalida]
	jmp	otroAnio
	
obtenerMes:
	mov	word[messalida],1
otroMes:
	call	obtenterDiasPorMes
	
	mov	ax,[diasJuliano]
	cmp ax,[cantdiasmes]
	jle	obtenerDia
	
	mov	dx,[cantdiasmes]
	sub	[diasJuliano],dx		; diasingreso - cantdiasmes
	inc	word[messalida]
	jmp	otroMes
	
obtenerDia:	
	mov	ax,[diasJuliano]
	mov	[diassalida],ax
	
ret

;----------------------------------------------------------
; Rutina para determinar la cantidad de dias según el año
; Param input: aniosalida
; Param output: cantdiasanio
;----------------------------------------------------------
obtenterDiasPorAnio:
	; lógica para determinar si el año bisiesto
	mov	dx,0	; pongo en 0 dx para la dupla dx:ax
	mov	ax,[aniosalida]
	idiv	word[cuatro]
	cmp	dx,0
	jne	nobisiesto	; si NO es divisible por 4 -> el año no es bisiesto
	
	mov	dx,0	; pongo en 0 dx para la dupla dx:ax
	mov	ax,[aniosalida]
	idiv	word[cien]
	cmp	dx,0
	je	divisiblecien	; si es divisible por 100 -> debo chequear si es divisible por 400
	jmp	bisiesto		; si NO es divisible por 100 y divisible por 4 -> el año es bisiesto
	
divisiblecien:
	mov	dx,0	; pongo en 0 dx para la dupla dx:ax
	mov	ax,[aniosalida]
	idiv	word[cuatrocien]
	cmp	dx,0
	jne	nobisiesto
	
bisiesto:
	mov	word[cantdiasanio],366
	mov	word[diasfebrero],29
	jmp	finRutina	
nobisiesto:
	mov	word[cantdiasanio],365
	mov	word[diasfebrero],28
finRutina:
ret

;----------------------------------------------------------
; Rutina para determinar la cantidad de dias según el mes
; Param input: messalida
; Param output: cantdiasmes
;----------------------------------------------------------
obtenterDiasPorMes:
	mov	ax,[messalida]
	cmp ax,1
	je	treintayundias
	cmp ax,2
	je	diasdefebrero
	cmp ax,3
	je	treintayundias
	cmp ax,4
	je	treintadias
	cmp ax,5
	je	treintayundias
	cmp ax,6
	je	treintadias
	cmp ax,7
	je	treintayundias
	cmp ax,8
	je	treintayundias
	cmp ax,9
	je	treintadias
	cmp ax,10
	je	treintayundias
	cmp ax,11
	je	treintadias
	cmp ax,12
	je	treintayundias
	
treintadias:
	mov	word[cantdiasmes],30
	jmp	finObtenerDiaMes
treintayundias:
	mov	word[cantdiasmes],31
	jmp	finObtenerDiaMes
diasdefebrero:
	mov dx,[diasfebrero]
	mov	word[cantdiasmes],dx
	
finObtenerDiaMes:
ret

;---------------------------
; Rutina para abrir archivo
;---------------------------
abrirArchivo:
	mov	al,0
	mov	dx,archin
	mov	ah,3dh
	int	21h
	jc	errOpen
	mov	[idarch],ax
	
ret

;-----------------------------
; Rutina para cerrar archivo
;-----------------------------
cerrarArchivo:
	mov	bx,[idarch]
	mov	ah,3eh
	int	21h
	jc	errClose

ret

;-----------------------------------------------------------------------------------
; Rutina para leer el archivo e imprimir por pantalla la fecha en gregoriano
;-----------------------------------------------------------------------------------
leer:
	otro:
		; leo registro del archivo
		mov	bx,[idarch]
		mov	cx,5
		mov	dx,reg
		mov	ah,3fh
		int	21h
		jc	errRead
		cmp	ax,0
		je	finArch
		
		call	convZonNum
		call	imprimirIngreso
		call	convertirAGregoriano
		call	imprimirFecha
		
		jmp	otro

finArch:
		;call	cerrarArchivo
ret

;------------------------------------------------
; Rutina para convertir Zoneado a BPF c/s
; Param input : reg zoneado de 5 bytes
; Param output : diasJuliano, anio, 
;------------------------------------------------
convZonNum:
	mov ax,0

    mov si,4
    mov al,byte[reg+si]
	
	shl al,4
	shr al,4
	
	mov [unidadanio],ax
	
	mov ax,0
    mov si,3
    mov al,byte[reg+si]

	shl al,4
	shr al,4
	mov bl,10
	imul bl
	mov [decenaanio],ax
	
	mov ax,0

    mov si,2
    mov al,byte[reg+si]
	
	shl al,4
	shr al,4

	mov [unidad],ax
	
	mov ax,0

    mov si,1
    mov al,byte[reg+si]

	shl al,4
	shr al,4

	mov bl,10
	imul bl
	
	mov [decena],ax
	
	mov ax,0

    mov si,0
    mov al,byte[reg+si]
	
	shl al,4
	shr al,4
	
	mov bl,100
	imul bl
	
	mov [centena],ax

	; obtengo el año del registro
	mov ax,0
	mov [anio],ax
	
    mov ax,word[unidadanio]
	add word[anio],ax
	
	mov ax,word[decenaanio]
	add word[anio],ax
	
	; obtengo la cantidad de días del registro
	mov ax,0
	mov [diasJuliano],ax

	mov ax,word[unidad]
	add word[diasJuliano],ax
	
	mov ax,word[decena]
	add word[diasJuliano],ax

	mov ax,word[centena]
	add word[diasJuliano],ax
	
ret

;----------------------------------------------------------
; Rutina para Imprimir Ingreso (fecha en formato Juliano).
; Param input: anio, diasJuliano
;----------------------------------------------------------
imprimirIngreso:
	mov	ax,[diasJuliano]
	mov	word[num],ax
	call	convertAscii
	
	mov	si,2			; contador para loop
otronumero1:
	mov	dl,[cadena +si]	
	mov	ah,2
	int	21h

	add	si,1		; me posiciono en el sgte elemento de cadena
	cmp	si,5
	jl	otronumero1
	
	; imprimo los ultimos dos digitos
	mov	ax,[anio]
	mov	word[num],ax
	call	convertAscii
	
	mov	si,3			; contador para loop
otronumero2:
	mov	dl,[cadena +si]
	mov	ah,2			; imprimo el elemento (de 'dl') en pantalla
	int	21h

	add	si,1			; me posiciono en el sgte elemento de cadena
	cmp	si,5
	jl	otronumero2
		
	lea	dx,[flecha]
	mov	ah,9
	int	21h

ret
	 
;-----------------------------------------------
; Rutina para Imprimir Salida en Formato Gregoriano.
; Param input: diassalida,messalida,aniosalida
;-----------------------------------------------
imprimirFecha:
	; imprimo los dias
	mov	ax,[diassalida]
	mov	word[num],ax
	
	call	convertAscii
	
	lea	dx,[cadena]
	mov	ah,9
	int	21h
	 
	lea	dx,[barra]
	mov	ah,9
	int	21h
	
	; imprimo el mes
	mov	ax,[messalida]
	mov	word[num],ax
	
	call	convertAscii
	
	lea	dx,[cadena]
	mov	ah,9
	int	21h
	
	lea	dx,[barra]
	mov	ah,9
	int	21h
	
	; imprimo el año
	mov	ax,[aniosalida]
	mov	word[num],ax
	
	call	convertAscii
	
	lea dx,[cadena]
	mov	ah,9
	int	21h
     
	lea	dx,[retornocarro]
	mov	ah,9
	int	21h
	 
ret

;-----------------------------------
; Rutina Convertir a Ascii
; param input:num
; param output:cadena
;-----------------------------------
convertAscii:
	; primero limpio la cadena
	mov si,4
	mov cx,5
	mov ax,0
	add ax,48
otrox:
	mov [cadena+si],al
	dec si
	loop otrox
	
	; comienzo del algoritmo para convertir a Ascii
	mov dx,0 ; pongo en 0 dx para la dupla dx:ax
	mov ax,word[num] ; copio el nro en AX para divisiones sucesivas
	mov si,4 ; 'si' apunta al ultimo byte de la cadena
	
	otraDiv:
	
		idiv word[diez] ; dx:ax div 10 ==> dx <- resto & ax <- cociente

		add	dx,48 			; convierto a Ascii el resto
		mov	[cadena+si],dl	; lo pongo en la posición anterior
		sub	si,1			; posiciono SI en el caracter anterior en la cadena
		
		cmp	ax,[diez]	; IF    cociente < 10
		jl	finDiv		; THEN  fin division
		
		mov	dx,0		; pongo en 0 DX para la dupla DX:AX
		jmp	otraDiv
	
	finDiv:
		add	ax,48
		mov	[cadena+si],al
		
ret

;----------------------------------
; Rutinas/Rotulos en caso de Error
;----------------------------------
errOpen:
errRead:
errWrite:
errClose:
showErr:
	lea	dx,[msgErr]
	mov	ah,9
	int	21h
	jmp	fin
	 
